github.com/ahmet2mir/goreleaser@v0.180.3-0.20210927151101-8e5ee5a9b8c5/internal/pipe/gomod/gomod proxy.go (about) 1 // Package gomod provides go modules utilities, such as template variables and the ability to proxy the module from 2 // proxy.golang.org. 3 package gomod 4 5 import ( 6 "errors" 7 "fmt" 8 "io" 9 "os" 10 "os/exec" 11 "path" 12 "path/filepath" 13 "strings" 14 15 "github.com/apex/log" 16 "github.com/goreleaser/goreleaser/internal/tmpl" 17 "github.com/goreleaser/goreleaser/pkg/config" 18 "github.com/goreleaser/goreleaser/pkg/context" 19 ) 20 21 // ProxyPipe for gomod proxy. 22 type ProxyPipe struct{} 23 24 func (ProxyPipe) String() string { return "proxying go module" } 25 26 func (ProxyPipe) Skip(ctx *context.Context) bool { 27 return ctx.ModulePath == "" || !ctx.Config.GoMod.Proxy || ctx.Snapshot 28 } 29 30 // Run the ProxyPipe. 31 func (ProxyPipe) Run(ctx *context.Context) error { 32 for i := range ctx.Config.Builds { 33 build := &ctx.Config.Builds[i] 34 if err := proxyBuild(ctx, build); err != nil { 35 return err 36 } 37 } 38 39 return nil 40 } 41 42 const goModTpl = ` 43 module {{ .BuildID }} 44 45 require {{ .ModulePath }} {{ .Tag }} 46 ` 47 48 const mainGoTpl = ` 49 // +build main 50 package main 51 52 import _ "{{ .Main }}" 53 ` 54 55 // ErrProxy happens when something goes wrong while proxying the current go module. 56 type ErrProxy struct { 57 err error 58 details string 59 } 60 61 func newErrProxy(err error) error { 62 return ErrProxy{ 63 err: err, 64 } 65 } 66 67 func newDetailedErrProxy(err error, details string) error { 68 return ErrProxy{ 69 err: err, 70 details: details, 71 } 72 } 73 74 func (e ErrProxy) Error() string { 75 out := fmt.Sprintf("failed to proxy module: %v", e.err) 76 if e.details != "" { 77 return fmt.Sprintf("%s: %s", out, e.details) 78 } 79 return out 80 } 81 82 func (e ErrProxy) Unwrap() error { 83 return e.err 84 } 85 86 func proxyBuild(ctx *context.Context, build *config.Build) error { 87 mainPackage := path.Join(ctx.ModulePath, build.Main) 88 if strings.HasSuffix(build.Main, ".go") { 89 pkg := path.Dir(build.Main) 90 log.Warnf("guessing package of '%s' to be '%s', if this is incorrect, setup 'build.%s.main' to be the correct package", build.Main, pkg, build.ID) 91 mainPackage = path.Join(ctx.ModulePath, pkg) 92 } 93 template := tmpl.New(ctx).WithExtraFields(tmpl.Fields{ 94 "Main": mainPackage, 95 "BuildID": build.ID, 96 }) 97 98 log.Infof("proxying %s@%s to build %s", ctx.ModulePath, ctx.Git.CurrentTag, mainPackage) 99 100 mod, err := template.Apply(goModTpl) 101 if err != nil { 102 return newErrProxy(err) 103 } 104 105 main, err := template.Apply(mainGoTpl) 106 if err != nil { 107 return newErrProxy(err) 108 } 109 110 dir := filepath.Join(ctx.Config.Dist, "proxy", build.ID) 111 112 log.Debugf("creating needed files") 113 114 if err := os.MkdirAll(dir, 0o755); err != nil { 115 return newErrProxy(err) 116 } 117 118 if err := os.WriteFile(filepath.Join(dir, "main.go"), []byte(main), 0o666); err != nil { 119 return newErrProxy(err) 120 } 121 122 if err := os.WriteFile(filepath.Join(dir, "go.mod"), []byte(mod), 0o666); err != nil { 123 return newErrProxy(err) 124 } 125 126 if err := copyGoSum("go.sum", filepath.Join(dir, "go.sum")); err != nil { 127 return newErrProxy(err) 128 } 129 130 log.Debugf("tidying") 131 cmd := exec.CommandContext(ctx, ctx.Config.GoMod.GoBinary, "mod", "tidy") 132 cmd.Dir = dir 133 cmd.Env = append(ctx.Config.GoMod.Env, os.Environ()...) 134 if out, err := cmd.CombinedOutput(); err != nil { 135 return newDetailedErrProxy(err, string(out)) 136 } 137 138 build.UnproxiedMain = build.Main 139 build.UnproxiedDir = build.Dir 140 build.Main = mainPackage 141 build.Dir = dir 142 return nil 143 } 144 145 func copyGoSum(src, dst string) error { 146 r, err := os.OpenFile(src, os.O_RDONLY, 0o666) 147 if err != nil { 148 if errors.Is(err, os.ErrNotExist) { 149 return nil 150 } 151 return err 152 } 153 defer r.Close() 154 155 w, err := os.Create(dst) 156 if err != nil { 157 return err 158 } 159 defer w.Close() 160 161 _, err = io.Copy(w, r) 162 return err 163 }